// main.vue 改为选项式 API
import { defineAsyncComponent, type ComponentPublicInstance, type InjectionKey, type AsyncComponentLoader } from 'vue';
import type { Emitter, EventType } from 'mitt';
import { createApp } from 'vue';
import MainComponent from './main.vue';
import ErrorComponent from './error.vue';
import i18n from '@/settings/i18n';
import store from '@/settings/stores';
import globalComponents from '@/settings/components';
import directive from '@/settings/directive';

export interface MyComponentPublicInstance extends ComponentPublicInstance {
  open: () => void;
  close: () => void;
  autoAdjustPosition: () => void;
  title: string;
  buttons: [] | object;
  hideClose: boolean;
  disabled: boolean;
  width: number;
  loading: boolean;
  error: string;
  ctx: any;
  emitter: Emitter<Record<EventType, unknown>>;
  $refs: {
    body: {
      dialogClickButton: (button: string) => void,
      dialogOptions: any,
    },
  };
}

export interface AsyncDialogResult {
  button: string;
  data?: any;
}

export interface AsyncDialogUtils {
  setError: () => void;
  autoAdjustPosition: () => void;
  setButton: (button: string, text: string) => void;
  setButtons: (buttons: Record<string, never>) => void;
  setTitle: (text: string) => void;
}

export interface AsyncDialogOptions {
  buttons?: [] | object;
  title?: string;
  hideClose?: boolean;
  props?: Record<string, any>;
  width?: number;
}

export const AsyncDialogProvide = Symbol() as InjectionKey<AsyncDialogUtils>;

export const dialog = (loader: AsyncComponentLoader, options: AsyncDialogOptions = {}): Promise<AsyncDialogResult> => {
  return new Promise((resolve) => {
    const boxComponent = {
      name: 'OpenAsyncDialog',
      extends: MainComponent,

      computed: {
        dialogProps() {
          return { ...options.props };
        },
      },

      components: {
        OpenAsyncDialogBody: defineAsyncComponent({
          // 加载函数
          loader,
          // 加载失败后展示的组件
          errorComponent: ErrorComponent,
        }),
      },
    };

    const app = createApp(boxComponent);
    app.config.errorHandler = (err: any) => {
      if (app._instance) {
        (app._instance as unknown as MyComponentPublicInstance).ctx.setError(err.message);
      }
    }
    app.use(i18n);
    app.use(store);
    app.use(globalComponents);
    app.use(directive);

    const box = app.mount(document.createElement('div')) as MyComponentPublicInstance;

    box.emitter.on('mounted', () => {
      box.loading = false;

      const instance = box.$refs.body;

      if (!instance) {
        return;
      }

      box.autoAdjustPosition();

      box.buttons = options?.buttons ?? instance.dialogOptions?.buttons ?? { ok: i18n.global.t('settings.component.dialog.button.ok'), cancel: i18n.global.t('settings.component.dialog.button.cancel') };
      box.title = options?.title ?? instance.dialogOptions?.title ?? i18n.global.t('settings.component.dialog.defaultTitle');
      box.hideClose = options?.hideClose ?? instance.dialogOptions?.hideClose ?? false;

      if (instance.dialogOptions?.width) {
        box.width = instance.dialogOptions.width;
      }
    });

    box.emitter.on('action', async function(button: any) {
      const instance = box.$refs.body;

      if (box.disabled || !instance) {
        return;
      }

      box.disabled = true;

      if (!instance.dialogClickButton) {
        box.close();

        resolve({ button });

        return;
      }

      const result: any = instance.dialogClickButton(button);

      if (result?.then) {
        result.then((result: any) => {
          if (typeof result === 'object') {
            if (result.close === true || typeof result.close === 'undefined') {
              box.close();

              resolve({ button, data: result });
            }
            else {
              box.disabled = false;
            }
          }
          else {
            if (result === true || typeof result === 'undefined') {
              box.close();

              resolve({ button, data: result });
            }
            else {
              box.disabled = false;
            }
          }
        });
      }
      else {
        if (typeof result === 'object') {
          if (result.close === true || typeof result.close === 'undefined') {
            box.close();

            resolve({ button, data: result });
          }
          else {
            box.disabled = false;
          }
        }
        else {
          if (result === true || typeof result === 'undefined') {
            box.close();

            resolve({ button, data: result });
          }
          else {
            box.disabled = false;
          }
        }
      }
    });

    box.emitter.on('close', () => {
      app.unmount();
    });

    if (options.width) {
      box.width = options.width;
    }

    box.title = i18n.global.t('settings.component.dialog.loading');
    box.open();
  });
}
